package org.yihang.annotation;

import org.yihang.util.SqlProperty;
import org.yihang.util.VoProperty;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static org.yihang.util.MapperGenerator.*;

public enum VoType {

    /**
     * 为true 时，会在按条件组合sql查询中添加条件
     * <pre>
     * 列名 &gt;= #{属性名}
     * </pre>
     */
    ge {
        @Override
        public String getSqlPart(SqlProperty sp) {
            return "<if test=\"" + sp.getProperty() + "!=" + sp.getValue() + "\"><![CDATA[ and " + sp.getColumn() + ">=#{" + sp.getProperty() + "}]]></if>";
        }

        @Override
        public List<VoProperty> getVoProperty(Field f, String p, String anno) {
            return Collections.singletonList(VoType.newVo(f, p, anno));
        }
    },
    /**
     * 为true 时，会在按条件组合sql查询中添加条件
     * <pre>
     * 列名 &gt; #{属性名}
     * </pre>
     */
    gt {
        @Override
        public String getSqlPart(SqlProperty sp) {
            return "<if test=\"" + sp.getProperty() + "!=" + sp.getValue() + "\"><![CDATA[ and " + sp.getColumn() + ">#{" + sp.getProperty() + "}]]></if>";
        }

        @Override
        public List<VoProperty> getVoProperty(Field f, String p, String anno) {
            return Collections.singletonList(VoType.newVo(f, p, anno));
        }
    },
    /**
     * 为true 时，会在按条件组合sql查询中添加条件
     * <pre>
     * 列名 &lt;= #{属性名}
     * </pre>
     */
    le {
        @Override
        public String getSqlPart(SqlProperty sp) {
            return "<if test=\"" + sp.getProperty() + "!=" + sp.getValue() + "\"><![CDATA[ and " + sp.getColumn() + "<=#{" + sp.getProperty() + "}]]></if>";
        }

        @Override
        public List<VoProperty> getVoProperty(Field f, String p, String anno) {
            return Collections.singletonList(VoType.newVo(f, p, anno));
        }
    },
    /**
     * 为true 时，会在按条件组合sql查询中添加条件
     * <pre>
     * 列名 &lt; #{属性名}
     * </pre>
     */
    lt {
        @Override
        public String getSqlPart(SqlProperty sp) {
            return "<if test=\"" + sp.getProperty() + "!=" + sp.getValue() + "\"><![CDATA[ and " + sp.getColumn() + "<#{" + sp.getProperty() + "}]]></if>";
        }

        @Override
        public List<VoProperty> getVoProperty(Field f, String p, String anno) {
            return Collections.singletonList(VoType.newVo(f, p, anno));
        }
    },
    /**
     * 为true 时，会在按条件组合sql查询中添加条件
     * <pre>
     * 列名 != #{属性名}
     * </pre>
     */
    ne {
        @Override
        public String getSqlPart(SqlProperty sp) {
            return "<if test=\"" + sp.getProperty() + "!=" + sp.getValue() + "\"><![CDATA[ and " + sp.getColumn() + "!=#{" + sp.getProperty() + "}]]></if>";
        }

        @Override
        public List<VoProperty> getVoProperty(Field f, String p, String anno) {
            return Collections.singletonList(VoType.newVo(f, p, anno));
        }
    },
    /**
     * 为true 时，会在按条件组合sql查询中添加like条件
     * <pre>
     * 列名 = #{属性名}
     * </pre>
     */
    eq {
        @Override
        public String getSqlPart(SqlProperty sp) {
            return "<if test=\"" + sp.getProperty() + "!=" + sp.getValue() + "\"><![CDATA[ and " + sp.getColumn() + "=#{" + sp.getProperty() + "}]]></if>";
        }

        @Override
        public List<VoProperty> getVoProperty(Field f, String p, String anno) {
            return Collections.singletonList(VoType.newVo(f, p, anno));
        }
    },
    /**
     * 为true 时，会在按条件组合sql查询中添加like条件
     * <pre>
     * 列名 like concat(#{属性名},'%')
     * </pre>
     */
    like {
        @Override
        public String getSqlPart(SqlProperty sp) {
            return "<if test=\"" + sp.getProperty() + "!=" + sp.getValue() + "\"><![CDATA[ and " + sp.getColumn() + " like concat(#{" + sp.getProperty() + "},'%')]]></if>";
        }

        @Override
        public List<VoProperty> getVoProperty(Field f, String p, String anno) {
            return Collections.singletonList(VoType.newVo(f, p, anno));
        }
    },
    /**
     * 为true 时，会在按条件组合sql查询中添加条件
     * <pre>
     * 列名 in &lt;foreach items="#{属性名}" var="i" open="(" close=")" &gt;#{i}&lt;/foreach&gt;
     * </pre>
     */
    in {
        @Override
        public String getSqlPart(SqlProperty sp) {
            return "<if test=\"" + sp.getProperty() + "!=" + sp.getValue() + " and " + sp.getProperty() + ".size()>0 \">" +
                    "<![CDATA[ and " + sp.getColumn() + " in ]]><foreach open=\"(\" close=\")\" separator=\",\" collection=\"" + sp.getProperty() + "\" item=\"it\">#{it}</foreach></if>";
        }

        @Override
        public List<VoProperty> getVoProperty(Field f, String p, String anno) {
            VoProperty vo = new VoProperty();
            vo.setName(p);
            vo.setType("java.util.List<" + getBoxedType(f.getType()).getCanonicalName() + ">");
            vo.setGetname(get(p));
            vo.setSetname(set(p));
            vo.setAnno(anno);
            return Collections.singletonList(vo);
        }
    },
    /**
     * 为true 时，会在按条件组合sql查询中添加条件
     * <pre>
     * 列名 between #{min属性名} and #{max属性名}
     * </pre>
     */
    between {
        @Override
        public String getSqlPart(SqlProperty sp) {
            String m1 = "min" + firstUpper(sp.getProperty());
            String m2 = "max" + firstUpper(sp.getProperty());
            return "<if test=\"" + m1 + "!=" + sp.getValue() + " and " + m2 + "!=" + sp.getValue() + "\"><![CDATA[ and " + sp.getColumn() + " between #{" + m1 + "} and #{" + m2 + "}]]></if>";
        }

        @Override
        public List<VoProperty> getVoProperty(Field f, String p, String anno) {
            String m1 = "min" + firstUpper(p);
            String m2 = "max" + firstUpper(p);
            return Arrays.asList(VoType.newVo(f, m1, anno), VoType.newVo(f, m2, anno));
        }
    };

    private static VoProperty newVo(Field field, String property, String anno) {
        VoProperty vo = new VoProperty();
        Class<?> type = getBoxedType(field.getType());
        vo.setName(property);
        vo.setType(type.getCanonicalName());
        vo.setAnno(anno);
        if (boolean.class == type) {
            vo.setGetname(is(property));
        } else {
            vo.setGetname(get(property));
        }
        vo.setSetname(set(property));
        return vo;
    }

    public abstract String getSqlPart(SqlProperty sp);

    public abstract List<VoProperty> getVoProperty(Field f, String p, String anno);
}
